using System;
using System.Xml;
using System.Collections.Generic;

namespace TJDevHouse.Starcraft.Game
{
	/// <summary> Stores tile information about a map in StarCraft.
	/// 
	/// Note: internally in StarCraft, the height and walkable arrays have a higher
	/// resolution than the size tile in this class. Each tile is actually
	/// a 4x4 grid, but this has been abstracted away for simplicity for now.
	/// </summary>
	public class Map
	{
		/// <summary>the map name </summary>
		virtual public System.String MapName { get; private set; }

		/// <summary>
		/// The unique hash for the map
		/// </summary>
		public int MapHash { get; private set; }

		/// <summary>
		/// The starting locations on the map
		/// </summary>
		virtual public List<StartingLocation> StartingLocations { get; private set; }

		/// <summary>number of build tiles wide </summary>
		virtual public int MapBuildWidth { get; private set; }

		/// <summary>number of build tiles high </summary>
		virtual public int MapBuildHeight { get; private set; }

		/// <summary>
		/// Walkable tiles high
		/// </summary>
		public int MapWalkableHeight {
			get
			{
				return MapBuildHeight * 4;
			}
		}

		/// <summary>
		/// Walkable tiles wide
		/// </summary>
		public int MapWalkableWidth
		{
			get
			{
				return MapBuildWidth * 4;
			}
		}

		/// <summary>
		/// All the minerals on the current map.
		/// </summary>
		public List<StaticMapResource> StaticMinerals { get; set; }

		/// <summary>
		/// All the vespene geysers on the current map.
		/// </summary>
		public List<StaticMapResource> StaticVespeneGeysers { get; set; }

		/// <summary>
		/// The walk tiles on the map.
		/// 
		/// Indexed [y,x]
		/// </summary>
		public WalkTile[,] WalkTiles { get; private set; }

		/// <summary>
		/// The build tiles on the map.
		/// 
		/// Indexed [y,x]
		/// </summary>
		public BuildTile[,] BuildTiles { get; private set; }


		public Map(int hash, string name, int width, int height)
		{
			MapHash = hash;
			MapName = name;
			MapBuildWidth = width;
			MapBuildHeight = height;

			BuildTiles = new BuildTile[MapBuildHeight, MapBuildWidth];
			WalkTiles = new WalkTile[MapWalkableHeight, MapWalkableWidth];

			StaticMinerals = new List<StaticMapResource>();
			StaticVespeneGeysers = new List<StaticMapResource>();
			StartingLocations = new List<StartingLocation>();

			//fill the tiles...
			for (int x = 0; x < MapWalkableWidth; x++)
			{
				for (int y = 0; y < MapWalkableHeight; y++)
				{
					WalkTiles[y, x] = new WalkTile(this, x, y);
					if (x % 4 == 0 && y % 4 == 0)
					{
						int bx = x / 4;
						int by = y / 4;
						BuildTiles[by, bx] = new BuildTile(this, bx, by);
					}
				}
			}
		}

		/// <summary>
		/// Checks whether the supplied coordinates are valid
		/// walk tile coordinates. (e.g. they're not off the map...)
		/// </summary>
		/// <param name="x"></param>
		/// <param name="y"></param>
		/// <returns></returns>
		public bool IsValidWalkTileCoord(int x, int y)
		{
			return (x >= 0 && y >= 0 && x < MapWalkableWidth && y < MapWalkableHeight);
		}

		/// <summary>
		/// Get a single build tile.
		/// 
		/// If the specified build tile is off the map, will return the nearest on map
		/// tile.
		/// </summary>
		/// <param name="x"></param>
		/// <param name="y"></param>
		/// <returns></returns>
		public BuildTile GetBuildTile(int x, int y)
		{
			if (x >= MapBuildWidth)
			{
				x = MapBuildWidth - 1;
			} else if (0 > x)
			{
				x = 0;
			}

			if (y >= MapBuildHeight)
			{
				y = MapBuildHeight - 1;
			}
			else if (0 > y)
			{
				y = 0;
			}
			return BuildTiles[y,x];
		}

		public BuildTile GetBuildTile(BuildTileMapCoordinate coord)
		{
			return GetBuildTile(coord.X, coord.Y);
		}

		/// <summary>
		/// Gets the build tile at the specified walk tile coordinates
		/// </summary>
		/// <param name="x"></param>
		/// <param name="y"></param>
		/// <returns></returns>
		public BuildTile GetBuildTileAtWalkTileCoords(int x, int y)
		{
			int bx = x / 4;
			int by = y / 4;

			return GetBuildTile(bx,by);
		}

		/// <summary>
		/// Get the walk tiles occupying the specified build tile
		/// </summary>
		/// <param name="x"></param>
		/// <param name="y"></param>
		/// <returns></returns>
		public List<WalkTile> GetWalkTilesAtBuildTileCoords(int x, int y)
		{
			List<WalkTile> tiles = new List<WalkTile>();
			for (int ix = 0; ix < 4; ix++)
			{
				for (int iy = 0; iy < 4; iy++)
				{
					tiles.Add(GetWalkTile((x * 4) + ix, (y * 4) + iy));
				}
			}
			return tiles;
		}

		/// <summary>
		/// Get a single walk tile
		/// </summary>
		/// <param name="x"></param>
		/// <param name="y"></param>
		/// <returns></returns>
		public WalkTile GetWalkTile(int x, int y)
		{
			return WalkTiles[y,x];
		}

		public WalkTile GetWalkTile(WalkTileMapCoordinate coords)
		{
			return GetWalkTile(coords.X, coords.Y);
		}

		protected StaticMapResource CreateStaticResource(UnitType type, BuildTileMapCoordinate coord)
		{
			return new StaticMapResource(type, GetBuildTile(coord));
		}

		public void AddStaticMineral(BuildTileMapCoordinate coord)
		{
			StaticMapResource res = CreateStaticResource(UnitType.Resource_Mineral_Field, coord);
			StaticMinerals.Add(res);
		}

		public void AddStaticGeyser(BuildTileMapCoordinate coord)
		{
			StaticMapResource res = CreateStaticResource(UnitType.Resource_Vespene_Geyser, coord);
			StaticVespeneGeysers.Add(res);
		}

		public void AddStartingLocation(BuildTileMapCoordinate coord)
		{
			StartingLocation sl = new StartingLocation(this, coord.X, coord.Y);
			StartingLocations.Add(sl);
		}
	}
}